home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume6 / shadow-2.pt2 < prev    next >
Encoding:
Text File  |  1989-02-03  |  32.5 KB  |  1,511 lines

  1. Path: xanth!nic.MR.NET!csd4.milw.wisc.edu!leah!itsgw!steinmetz!uunet!allbery
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Newsgroups: comp.sources.misc
  4. Subject: v06i023: shadow password routines, part 2
  5. Message-ID: <47755@uunet.UU.NET>
  6. Date: 29 Jan 89 21:12:45 GMT
  7. Sender: allbery@uunet.UU.NET
  8. Reply-To: jfh@hal.CWRU.Edu@convex.UUCP (John F. Haugh II)
  9. Lines: 1499
  10. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  11.  
  12. Posting-number: Volume 6, Issue 23
  13. Submitted-by: jfh@hal.CWRU.Edu@convex.UUCP (John F. Haugh II)
  14. Archive-name: shadow-2.pt2
  15.  
  16. [No Subject: line -- biggest violation in the rulebook.  How am I supposed
  17. to know this is multipart ahead of schedule?  ++bsa]
  18.  
  19. #! /bin/sh
  20. # This is a shell archive, meaning:
  21. # 1. Remove everything above the #! /bin/sh line.
  22. # 2. Save the resulting text in a file.
  23. # 3. Execute the file with /bin/sh (not csh) to create:
  24. #    log.c
  25. #    mail.c
  26. #    shadow.h
  27. #    sulog.c
  28. #    Makefile
  29. #    entry.c
  30. #    obscure.c
  31. #    setup.c
  32. #    sub.c
  33. #    config.h
  34. #    shadow.info
  35. #    pmain.c
  36. #    sulogin.c
  37. #    dialup.h
  38. # This archive created: Sun Jan 22 22:24:51 1989
  39. # By:    John F. Haugh II (River Parishes Programming, Dallas TX)
  40. export PATH; PATH=/bin:/usr/bin:$PATH
  41. if test -f 'log.c'
  42. then
  43.     echo shar: "will not over-write existing file 'log.c'"
  44. else
  45. cat << \SHAR_EOF > 'log.c'
  46. #include <sys/types.h>
  47. #include <utmp.h>
  48. #include <pwd.h>
  49. #include <fcntl.h>
  50. #include <time.h>
  51. #include <string.h>
  52. #include "config.h"
  53.  
  54. extern    struct    utmp    utent;
  55. extern    struct    passwd    pwent;
  56. extern    struct    lastlog    lastlog;
  57. extern    char    **environ;
  58.  
  59. long    lseek ();
  60. time_t    time ();
  61.  
  62. #ifdef    LASTLOG
  63.  
  64. #include "lastlog.h"
  65.  
  66. void    log ()
  67. {
  68.     int    fd;
  69.     long    offset;
  70.     struct    lastlog    newlog;
  71.  
  72.     if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1)
  73.         return;
  74.  
  75.     offset = pwent.pw_uid * sizeof lastlog;
  76.  
  77.     if (lseek (fd, offset, 0) != offset)
  78.         return;
  79.  
  80.     if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog)
  81.         memset ((char *) &lastlog, sizeof lastlog, 0);
  82.  
  83.     newlog = lastlog;
  84.  
  85.     (void) time (&newlog.ll_time);
  86.     (void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line);
  87.     (void) lseek (fd, offset, 0);
  88.     (void) write (fd, (char *) &newlog, sizeof newlog);
  89.     (void) close (fd);
  90. }
  91. #endif
  92. SHAR_EOF
  93. fi
  94. if test -f 'mail.c'
  95. then
  96.     echo shar: "will not over-write existing file 'mail.c'"
  97. else
  98. cat << \SHAR_EOF > 'mail.c'
  99. #include <sys/types.h>
  100. #include <sys/stat.h>
  101. #include <string.h>
  102. #include "config.h"
  103.  
  104. extern    char    mail[];
  105.  
  106. #ifdef    MAILCHECK
  107. void    mailcheck ()
  108. {
  109.     struct    stat    statbuf;
  110.     char    *mailbox;
  111.  
  112.     if (mailbox = strchr (mail, '='))
  113.         mailbox++;
  114.     else
  115.         return;
  116.  
  117.     if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0)
  118.         puts ("No mail.");
  119.     else if (statbuf.st_atime > statbuf.st_mtime)
  120.         puts ("You have mail.");
  121.     else
  122.         puts ("You have new mail.");
  123. }
  124. #endif
  125. SHAR_EOF
  126. fi
  127. if test -f 'shadow.h'
  128. then
  129.     echo shar: "will not over-write existing file 'shadow.h'"
  130. else
  131. cat << \SHAR_EOF > 'shadow.h'
  132. /*
  133.  * This information is not derived from AT&T licensed sources.  Posted
  134.  * to the USENET 11/88.
  135.  */
  136.  
  137. /*
  138.  * Shadow password security file structure.
  139.  */
  140.  
  141. struct    spwd {
  142.     char    *sp_namp;    /* login name */
  143.     char    *sp_pwdp;    /* encrypted password */
  144.     long    sp_lstchg;    /* date of last change */
  145.     int    sp_max;        /* maximum number of days between changes */
  146.     int    sp_min;        /* minimum number of days between changes */
  147. };
  148.  
  149. /*
  150.  * Shadow password security file functions.
  151.  */
  152.  
  153. struct    spwd    *getspent ();
  154. struct    spwd    *getspnam ();
  155. void    setspent ();
  156. void    endspent ();
  157. struct    spwd    *fgetspent ();
  158. int    putspent ();
  159.  
  160. #define  SHADOW "/etc/shadow"
  161. SHAR_EOF
  162. fi
  163. if test -f 'sulog.c'
  164. then
  165.     echo shar: "will not over-write existing file 'sulog.c'"
  166. else
  167. cat << \SHAR_EOF > 'sulog.c'
  168. #include <sys/types.h>
  169. #include <stdio.h>
  170. #include <time.h>
  171. #include <string.h>
  172. #include "config.h"
  173.  
  174. extern    char    name[];
  175. extern    char    oldname[];
  176.  
  177. time_t    time ();
  178.  
  179. void    sulog (success)
  180. int    success;
  181. {
  182. #ifdef    SULOG
  183.     char    *tty;
  184.     char    *cp;
  185.     char    *ttyname ();
  186.     time_t    clock;
  187.     struct    tm    *tm;
  188.     struct    tm    *localtime ();
  189.     FILE    *fp;
  190.  
  191.     if ((fp = fopen (SULOG, "a+")) == (FILE *) 0)
  192.         return;            /* can't open or create logfile */
  193.  
  194.     (void) time (&clock);
  195.     tm = localtime (&clock);
  196.  
  197.     if (isatty (0) && (cp = ttyname (0))) {
  198.         if (tty = strrchr (cp, '/'))
  199.             tty++;
  200.         else
  201.             tty = cp;
  202.     } else
  203.         tty = "???";
  204.  
  205.     (void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n",
  206.         tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
  207.         success ? '+':'-', tty, oldname, name);
  208.  
  209.     fflush (fp);
  210.     fclose (fp);
  211. #endif
  212. }
  213. SHAR_EOF
  214. fi
  215. if test -f 'Makefile'
  216. then
  217.     echo shar: "will not over-write existing file 'Makefile'"
  218. else
  219. cat << \SHAR_EOF > 'Makefile'
  220. SHELL = /bin/sh
  221.  
  222. # Flags for SCO Xenix/386
  223. CFLAGS = -O -M3 -g -DFGETPWENT
  224. LIBS = -lcrypt
  225. LDFLAGS = -M3 -g
  226. LTFLAGS = 
  227.  
  228. # Flags for normal machines
  229. # CFLAGS = -O -g
  230. # LIBS =
  231. # LDFLAGS = -g
  232.  
  233. LOBJS = lmain.o login.o env.o password.o entry.o valid.o setup.o shell.o age.o \
  234.     pwent.o utmp.o sub.o mail.o motd.o log.o shadow.o dialup.o dialchk.o
  235.  
  236. LSRCS = lmain.c login.c env.c password.c entry.c valid.c setup.c shell.c age.c \
  237.     pwent.c utmp.c sub.c mail.c motd.c log.c shadow.c dialup.o dialchk.o
  238.  
  239. SOBJS = smain.o env.o password.o entry.o valid.o susetup.o sushell.o \
  240.     pwent.o susub.o mail.o motd.o sulog.o shadow.o age.o
  241.  
  242. SSRCS = smain.c env.c password.c entry.c valid.c setup.c shell.c \
  243.     pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c
  244.  
  245. POBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o
  246.  
  247. PSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c
  248.  
  249. PWOBJS = pwconv.o pwent.o shadow.o pwage.o
  250.  
  251. PWSRCS = pwconv.c pwent.c shadow.c age.c
  252.  
  253. PWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o
  254.  
  255. PWUNSRCS = pwunconv.c pwent.c shadow.c age.c
  256.  
  257. SULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \
  258.     shadow.o shell.o valid.o
  259.  
  260. SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \
  261.     shadow.c shell.c valid.c
  262.  
  263. FILES1 = log.c mail.c shadow.h sulog.c Makefile entry.c obscure.c \
  264.     setup.c sub.c config.h shadow.info pmain.c sulogin.c dialup.h
  265.  
  266. FILES2 = lastlog.h login.c motd.c password.c shell.c utmp.c age.c env.c \
  267.     pwent.c shadow.c valid.c lmain.c smain.c pwconv.c dialup.c dialchk.c \
  268.     pwunconv.c
  269.  
  270. DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \
  271.     pwunconv.8
  272.  
  273. all:    su login pwconv pwunconv passwd sulogin
  274.  
  275. lint:    su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L
  276.  
  277. login:    $(LOBJS)
  278.     cc -o login $(LDFLAGS) $(LOBJS) $(LIBS)
  279.  
  280. login.L: $(LSRCS)
  281.     lint $(LSRCS) > login.L
  282.  
  283. su:    $(SOBJS)
  284.     cc -o su $(LDFLAGS) $(SOBJS) $(LIBS)
  285.  
  286. su.L:    $(SSRCS)
  287.     lint -DSU $(SSRCS) > su.L
  288.  
  289. passwd:    $(POBJS)
  290.     cc -o passwd $(LDFLAGS) $(POBJS) $(LIBS)
  291.  
  292. passwd.L: $(PSRCS)
  293.     lint -DPASSWD $(PSRCS) > passwd.L
  294.  
  295. pwconv:    $(PWOBJS)
  296.     cc -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)
  297.  
  298. pwconv.L: $(PWSRCS)
  299.     lint -DPASSWD $(PWSRCS) > pwconv.L
  300.  
  301. pwunconv: $(PWUNOBJS)
  302.     cc -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)
  303.  
  304. pwunconv.L: $(PWUNSRCS)
  305.     lint -DPASSWD $(PWUNSRCS) > pwunconv.L
  306.  
  307. sulogin: $(SULOGOBJS)
  308.     cc -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)
  309.  
  310. sulogin.L: $(SULOGSRCS)
  311.     lint $(SULOGSRCS) > sulogin.L
  312.  
  313. sushell.o: config.h shell.c
  314.     cc -c $(CFLAGS) -DSU shell.c
  315.     mv shell.o sushell.o
  316.  
  317. susub.o: config.h sub.c
  318.     cc -c $(CFLAGS) -DSU sub.c
  319.     mv sub.o susub.o
  320.  
  321. sulog.o: config.h
  322.  
  323. susetup.o: config.h setup.c
  324.     cc -c $(CFLAGS) -DSU setup.c
  325.     mv setup.o susetup.o
  326.  
  327. pmain.o: config.h lastlog.h shadow.h
  328.  
  329. pwage.o: age.c config.h
  330.     cp age.c pwage.c
  331.     cc -c $(CFLAGS) -DPASSWD pwage.c
  332.     rm pwage.c
  333.  
  334. lmain.o: config.h lastlog.h
  335.  
  336. setup.o: config.h
  337.  
  338. utmp.o: config.h
  339.  
  340. mail.o: config.h
  341.  
  342. motd.o: config.h
  343.  
  344. age.o: config.h
  345.  
  346. log.o: config.h lastlog.h
  347.  
  348. shell.o: config.h
  349.  
  350. entry.o: config.h shadow.h
  351.  
  352. shadow.o: shadow.h
  353.  
  354. dialup.o: dialup.h
  355.  
  356. dialchk.o: dialup.h config.h
  357.  
  358. clean:
  359.     -rm -f *.o a.out core npasswd nshadow
  360.  
  361. clobber: clean
  362.     -rm -f su login passwd pwconv pwunconv sulogin *.L
  363.  
  364. shar:    login.sh.1 login.sh.2 login.sh.3
  365.  
  366. login.sh.1: $(FILES1)
  367.     shar $(FILES1) > login.sh.1
  368.  
  369. login.sh.2: $(FILES2)
  370.     shar $(FILES2) > login.sh.2
  371.  
  372. login.sh.3: $(DOCS)
  373.     shar $(DOCS) > login.sh.3
  374. SHAR_EOF
  375. fi
  376. if test -f 'entry.c'
  377. then
  378.     echo shar: "will not over-write existing file 'entry.c'"
  379. else
  380. cat << \SHAR_EOF > 'entry.c'
  381. #include <stdio.h>
  382. #include <pwd.h>
  383. #include <string.h>
  384. #include "config.h"
  385. #ifdef    SHADOWPWD
  386. #include "shadow.h"
  387. #endif
  388.  
  389. struct    passwd    *fgetpwent ();
  390. char    *malloc ();
  391.  
  392. char    *strdup (s)
  393. char    *s;
  394. {
  395.     char    *cp;
  396.  
  397.     if (s == (char *) 0)
  398.         return ((char *) 0);
  399.  
  400.     if (! (cp = malloc ((unsigned) strlen (s) + 1)))
  401.         return ((char *) 0);
  402.  
  403.     return (strcpy (cp, s));
  404. }
  405.  
  406. void    entry (name, pwent)
  407. char    *name;
  408. struct    passwd    *pwent;
  409. {
  410.     FILE    *pwd;
  411.     struct    passwd    *passwd;
  412. #ifdef    SHADOWPWD
  413.     struct    spwd    *spwd;
  414.     char    *l64a ();
  415. #endif
  416.     char    *cp;
  417.  
  418.     if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
  419.         pwent->pw_passwd = (char *) 0;
  420.         return;
  421.     }
  422.     while (passwd = fgetpwent (pwd)) {
  423.         if (strcmp (name, passwd->pw_name) == 0)
  424.             break;
  425.     }
  426.     fclose (pwd);
  427.  
  428.     if (passwd == (struct passwd *) 0) {
  429.         pwent->pw_name = (char *) 0;
  430.         pwent->pw_passwd = (char *) 0;
  431.     } else  {
  432.         pwent->pw_name = strdup (passwd->pw_name);
  433.         pwent->pw_uid = passwd->pw_uid;
  434.         pwent->pw_gid = passwd->pw_gid;
  435.         pwent->pw_comment = (char *) 0;
  436.         pwent->pw_gecos = strdup (passwd->pw_gecos);
  437.         pwent->pw_dir = strdup (passwd->pw_dir);
  438.         pwent->pw_shell = strdup (passwd->pw_shell);
  439. #ifdef    SHADOWPWD
  440.         setspent ();
  441.         if (spwd = getspnam (name)) {
  442.             pwent->pw_passwd = strdup (spwd->sp_pwdp);
  443.             if (spwd->sp_lstchg == 0) {
  444.                 pwent->pw_age = (char *) 0;
  445.                 endspent ();
  446.                 return;
  447.             }
  448.             pwent->pw_age = malloc (5);
  449.             pwent->pw_age[0] = i64c (spwd->sp_max / 7);
  450.             pwent->pw_age[1] = i64c (spwd->sp_min / 7);
  451.             cp = l64a (spwd->sp_lstchg / 7);
  452.             pwent->pw_age[2] = cp[0];
  453.             pwent->pw_age[3] = cp[1];
  454.             pwent->pw_age[4] = '\0';
  455.             endspent ();
  456.             return;
  457.         }
  458.         endspent ();
  459.         passwd->pw_age = pwent->pw_age = (char *) 0;
  460. #endif
  461.         if (passwd->pw_passwd)
  462.             pwent->pw_passwd = strdup (passwd->pw_passwd);
  463.  
  464.         if (passwd->pw_age) {
  465.             pwent->pw_age = malloc (5);    /* longest legal time */
  466.             (void) strncpy (pwent->pw_age, passwd->pw_age, 5);
  467.         } else
  468.             pwent->pw_age = (char *) 0;
  469.     }
  470. }
  471. SHAR_EOF
  472. fi
  473. if test -f 'obscure.c'
  474. then
  475.     echo shar: "will not over-write existing file 'obscure.c'"
  476. else
  477. cat << \SHAR_EOF > 'obscure.c'
  478. #include <ctype.h>
  479. #include "config.h"
  480.  
  481. /*
  482.  * Obscure - see if password is obscure enough.
  483.  *
  484.  *    The programmer is encouraged to add as much complexity to this
  485.  *    routine as desired.  Included are some of my favorite ways to
  486.  *    check passwords.
  487.  */
  488.  
  489. extern    char    pass[];            /* the new password */
  490. extern    char    orig[];            /* the original password */
  491. char    mono[32];            /* a monocase version of pass */
  492.  
  493. int    obscure ()
  494. {
  495.     int    i;
  496.  
  497.     if (orig[0] == '\0')
  498.         return (1);
  499.  
  500.     if (strlen (pass) < 6) {    /* too short */
  501.         printf ("Too short.  ");
  502.         return (0);
  503.     }
  504. #ifdef    OBSCURE
  505.     for (i = 0;pass[i];i++)
  506.         mono[i] = tolower (pass[i]);
  507.  
  508.     if (strcmp (pass, orig) == 0)    /* the same */
  509.         return (0);
  510.  
  511.     if (palindrome ())        /* a palindrome */
  512.         return (0);
  513.  
  514.     if (caseshift ())        /* upper/lower case changes only */
  515.         return (0);
  516.  
  517.     if (similiar ())        /* jumbled version of original */
  518.         return (0);
  519. #endif
  520.     return (1);
  521. }
  522.  
  523. #ifdef    OBSCURE
  524.  
  525. /*
  526.  * can't be a palindrome - like `R A D A R' or `M A D A M'
  527.  */
  528.  
  529. int    palindrome ()
  530. {
  531.     int    i, j;
  532.  
  533.     i = strlen (pass);
  534.  
  535.     for (j = 0;j < i;j++)
  536.         if (pass[i - j - 1] != pass[j])
  537.             return (0);
  538.  
  539.     printf ("No palindromes.  ");
  540.     return (1);
  541. }
  542.  
  543. /*
  544.  * may not be a shifted version of original
  545.  */
  546.  
  547. int    caseshift ()
  548. {
  549.     int    i;
  550.  
  551.     for (i = 0;pass[i] && orig[i];i++) {
  552.         if (tolower (pass[i]) == tolower (orig[i]))
  553.             continue;
  554.         else
  555.             return (0);
  556.     }
  557.     printf ("May not be case-shifted.  ");
  558.     return (1);
  559. }
  560.  
  561. /*
  562.  * more than half of the characters are different ones.
  563.  */
  564.  
  565. int    similiar ()
  566. {
  567.     int    i, j;
  568.     char    *strchr ();
  569.  
  570.     for (i = j = 0;pass[i] && orig[i];i++)
  571.         if (strchr (mono, tolower (orig[i])))
  572.             j++;
  573.  
  574.     if (i - j > 2)
  575.         return (0);
  576.  
  577.     printf ("Too similiar.  ");
  578.     return (1);
  579. }
  580. #endif
  581. SHAR_EOF
  582. fi
  583. if test -f 'setup.c'
  584. then
  585.     echo shar: "will not over-write existing file 'setup.c'"
  586. else
  587. cat << \SHAR_EOF > 'setup.c'
  588. #include <sys/types.h>
  589. #include <pwd.h>
  590. #include <utmp.h>
  591. #include <string.h>
  592. #include "config.h"
  593.  
  594. extern    char    home[];
  595. extern    char    prog[];
  596. extern    char    name[];
  597. extern    char    mail[];
  598.  
  599. #ifndef    SU
  600. extern    struct    utmp    utent;
  601. #endif
  602.  
  603. #ifdef    QUOTAS
  604. long    strtol ();
  605. long    ulimit ();
  606. #endif
  607.  
  608. void    addenv ();
  609.  
  610. void    setup (info)
  611. struct    passwd    *info;
  612. {
  613.     extern    int    errno;
  614.     char    logname[30];
  615. #ifndef    SU
  616.     char    tty[30];
  617. #endif
  618.     char    *cp;
  619.     int    i;
  620.     long    l;
  621.  
  622. #ifndef    SU
  623.     (void) strcat (strcpy (tty, "/dev/"), utent.ut_line);
  624.     if (chown (tty, info->pw_uid, info->pw_gid) ||
  625.                     chmod (tty, TTYPERM))
  626.         perror (tty);
  627. #endif
  628.     if (chdir (info->pw_dir) == -1) {
  629.         (void) printf ("Unable to change directory to \"%s\"\n", info->pw_dir);
  630.         exit (errno);
  631.     }
  632. #ifdef    QUOTAS
  633.     for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) {
  634.         if (*cp == ',')
  635.             cp++;
  636.  
  637.         if (strncmp (cp, "pri=", 4) == 0) {
  638.             i = atoi (cp + 4);
  639.             if (i >= -20 && i <= 20)
  640.                 (void) nice (i);
  641.  
  642.             continue;
  643.         }
  644.         if (strncmp (cp, "ulimit=", 6) == 0) {
  645.             l = strtol (cp + 6, (char **) 0, 10);
  646.             (void) ulimit (2, l);
  647.  
  648.             continue;
  649.         }
  650.         if (strncmp (cp, "umask=", 5) == 0) {
  651.             i = strtol (cp + 5, (char **) 0, 8) & 0777;
  652.             (void) umask (i);
  653.  
  654.             continue;
  655.         }
  656.     }
  657. #endif
  658.     if (setgid (info->pw_gid) == -1) {
  659.         puts ("Bad group id");
  660.         exit (errno);
  661.     }
  662.     if (setuid (info->pw_uid) == -1) {
  663.         puts ("Bad user id");
  664.         exit (errno);
  665.     }
  666.     (void) strcat (strcpy (home, "HOME="), info->pw_dir);
  667.     addenv (home);
  668.  
  669.     if (info->pw_shell == (char *) 0)
  670.         info->pw_shell = "/bin/sh";
  671.  
  672.     (void) strcat (strcpy (prog, "SHELL="), info->pw_shell);
  673.     addenv (prog);
  674.  
  675.     if (info->pw_uid == 0)
  676.         addenv (SUPATH);
  677.     else
  678.         addenv (PATH);
  679.  
  680. #ifndef    SU
  681.     (void) strcat (strcpy (logname, "LOGNAME="), name);
  682.     addenv (logname);
  683. #endif
  684.     (void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name);
  685.     addenv (mail);
  686. }
  687. SHAR_EOF
  688. fi
  689. if test -f 'sub.c'
  690. then
  691.     echo shar: "will not over-write existing file 'sub.c'"
  692. else
  693. cat << \SHAR_EOF > 'sub.c'
  694. #include <sys/types.h>
  695. #include <pwd.h>
  696. #include <utmp.h>
  697. #include <string.h>
  698.  
  699. extern    struct    passwd    pwent;
  700. #ifndef    SU
  701. extern    struct    utmp    utent;
  702. #endif
  703.  
  704. void    setutmp ();
  705.  
  706. /*
  707.  * I have heard of two different types of behavior with subsystem roots.
  708.  * One has you execute login no matter what.  The other has you execute
  709.  * the command [ if one exists ] after the '*' in the shell name.  The
  710.  * macro SUBLOGIN says to execute /bin/login [ followed by /etc/login ]
  711.  * regardless.  Otherwise, pwent.pw_shell is fixed up and that command
  712.  * is executed [ by returning to the caller ].  I prefer the latter since
  713.  * it doesn't require having a "login" on the new root filesystem.
  714.  */
  715.  
  716. void    subsystem ()
  717. {
  718.     char    *strdup ();
  719.  
  720.     if (chdir (pwent.pw_dir) || chroot (pwent.pw_dir)) {
  721.         printf ("Can't change to \"%s\"\n", pwent.pw_dir);
  722.         exit (1);
  723.     }
  724. #ifndef    SU
  725.     (void) strcpy (utent.ut_line, "<!sublogin>");
  726.  
  727.     setutmp ();
  728. #endif
  729. #ifdef    SUBLOGIN
  730.     execl ("/bin/login", "login", name, (char *) 0);
  731.     execl ("/etc/login", "login", name, (char *) 0);
  732.     puts ("No /bin/login or /etc/login on root");
  733.     exit (1);
  734. #else
  735.     if (pwent.pw_shell[1] == '\0')
  736.         pwent.pw_shell = "/bin/sh";
  737.     else
  738.         pwent.pw_shell++;
  739. #endif
  740. }
  741. SHAR_EOF
  742. fi
  743. if test -f 'config.h'
  744. then
  745.     echo shar: "will not over-write existing file 'config.h'"
  746. else
  747. cat << \SHAR_EOF > 'config.h'
  748. /*
  749.  * Configuration file for login.
  750.  */
  751.  
  752. /*
  753.  * Define DIALUP to use dialup password files
  754.  */
  755.  
  756. #define    DIALUP
  757.  
  758. /*
  759.  * Define SHADOWPWD to use shadow [ unreadable ] password file
  760.  */
  761.  
  762. #define    SHADOWPWD
  763.  
  764. /*
  765.  * Define OBSCURE to include hard password testing code.
  766.  */
  767.  
  768. #define    OBSCURE
  769.  
  770. /*
  771.  * Define PASSLENGTH to be shortest legal password
  772.  */
  773.  
  774. #define    PASSLENGTH    5
  775.  
  776. /*
  777.  * Define NOBLANK if you want all passwords prompted for, including
  778.  * empty ones.
  779.  
  780. #undef    NOBLANK
  781.  
  782. /*
  783.  * Define NDEBUG for production versions
  784.  */
  785.  
  786. #define    NDEBUG
  787.  
  788. /*
  789.  * Define HZ if login must set HZ value
  790.  */
  791.  
  792. #define    HZ    "HZ=50"
  793.  
  794. /*
  795.  * Define TZ if login must set timezone
  796.  */
  797.  
  798. #define    TZ    "TZ=CST6CDT"
  799.  
  800. /*
  801.  * Define the default PATH and SUPATH here.  PATH is for non-privileged
  802.  * users, SUPATH is for root.
  803.  */
  804.  
  805. #define    PATH    "PATH=:/bin:/usr/bin"
  806. #define    SUPATH    "PATH=:/bin:/usr/bin:/etc"
  807.  
  808. /*
  809.  * Define the mailbox directory
  810.  */
  811.  
  812. #define    MAILDIR    "/usr/spool/mail/"
  813.  
  814. /*
  815.  * Define AGING if you want the password aging checks made.
  816.  */
  817.  
  818. #define    AGING
  819.  
  820. /*
  821.  * Define MAILCHECK if you want the mailbox checked for new mail
  822.  *
  823.  * One of two messages are printed - `You have new mail.' or
  824.  * `You have mail.'.
  825.  */
  826.  
  827. #define    MAILCHECK
  828.  
  829. /*
  830.  * Define CONSOLE if you want ROOT restricted to a single terminal
  831.  */
  832.  
  833. #define    CONSOLE    "tty01"
  834.  
  835. /*
  836.  * Define MOTD if you want the message of the day (/etc/motd) printed
  837.  * at login time.
  838.  */
  839.  
  840. #define    MOTD
  841.  
  842. /*
  843.  * Define HUSHLOGIN if you want the code added to avoid printing the
  844.  * motd if a file $HOME/.hushlogin exists.  This obviously only matters
  845.  * if MOTD is #define'd.
  846.  */
  847.  
  848. #define    HUSHLOGIN
  849.  
  850. /*
  851.  * Define LASTLOG if you want a record made of logins in /usr/adm/lastlog.
  852.  */
  853.  
  854. #define    LASTLOG
  855.  
  856. /*
  857.  * Define TTYPERM to be the initial terminal permissions.  Defining
  858.  * as 0600 will not allow messages, 0622 will.
  859.  */
  860.  
  861. #define    TTYPERM    0600
  862.  
  863. /*
  864.  * Define QUOTAS if you want the code added in setup.c to support
  865.  * file ulimit and nice [ and umask as well ] setting from the password
  866.  * file.
  867.  */
  868.  
  869. #define    QUOTAS
  870.  
  871. /*
  872.  * Define file name for sulog.  If SULOG is not defined, there will be
  873.  * no logging.  This is NOT a good idea ...  We also define other file
  874.  * names.
  875.  */
  876.  
  877. #define    SULOG    "/usr/adm/sulog"
  878. #define    PWDFILE    "/etc/passwd"
  879. #define    OPWDFILE "/etc/-passwd"
  880. #define    NPWDFILE "/etc/npasswd"
  881. #define    OSHADOW "/etc/-shadow"
  882. #define    NSHADOW "/etc/nshadow"
  883.  
  884. /*
  885.  * Define PWDLOCK to be a locking semaphore for updating the password
  886.  * file.
  887.  */
  888.  
  889. #define    PWDLOCK    "/etc/.pwdlock"
  890. SHAR_EOF
  891. fi
  892. if test -f 'shadow.info'
  893. then
  894.     echo shar: "will not over-write existing file 'shadow.info'"
  895. else
  896. cat << \SHAR_EOF > 'shadow.info'
  897. >From vector!killer!osu-cis!att!cuuxb!dlm Sun Nov 13 08:11:08 CST 1988
  898. Article 5025 of comp.unix.wizards:
  899. Path: rpp386!vector!killer!osu-cis!att!cuuxb!dlm
  900. >From: dlm@cuuxb.ATT.COM (Dennis L. Mumaugh)
  901. Newsgroups: comp.unix.wizards
  902. Subject: /etc/shadow
  903. Summary: See release notes for SVR3.2
  904. Keywords: shadow password
  905. Message-ID: <2189@cuuxb.ATT.COM>
  906. Date: 11 Nov 88 21:33:37 GMT
  907. References: <16722@agate.BERKELEY.EDU> <2178@cuuxb.ATT.COM> <16768@agate.BERKELEY.EDU> <17828@glacier.STANFORD.EDU> <2182@cuuxb.ATT.COM> <8
  908. Reply-To: dlm@cuuxb.UUCP (Dennis L. Mumaugh)
  909. Organization: ATT Data Systems Group, Lisle, Ill.
  910. Lines: 60
  911.  
  912. In article <8861@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
  913. >It would be a great service to the community if specifications for
  914. >this feature were posted or at least sent to developers who want
  915. >to enable a similar feature on their (typically BSD-based) systems.
  916. >For example, what is the shadow file called, what is its format,
  917. >what sort of stuff is left in the password field in /etc/passwd,
  918. >what facilities are there to validate a password against the
  919. >shadow encrypted password file?
  920.  
  921. The documentation is scattered in the Release Notes for System V
  922. Release 3.2.  Of course they don't have a page shadow(4) but:
  923.  
  924. The file is /etc/shadow and is owned by root and mode 400.
  925. It contains one line per login.  Fields are separated by colons:
  926.     username \- users login name
  927.     password \- A 13 character encrypted password or a lock string to
  928.             indicater the login is not accessible
  929.     lastchanged \- number of days since January 1, 1970 that the password
  930.                    has been modified
  931.     min \- the number of days required between password changes
  932.     max \- the maximum number of days the password is valid.
  933.  
  934. Routines to work with /etc/shadow:
  935.     #include <shadow.h>
  936.     struct spwd *getspent();
  937.     struct spwd *getspnam(char * name);
  938.     void setspent();
  939.     void endspent();
  940.     struct spwd *fgetspent(FILE *fp);
  941.     int putspent(struct spwd *p,FILE *fp);
  942.  
  943. Programs allied with this are 
  944.     pwconv \- install and/or update /etc/shadow with information
  945.           from /etc/passwd
  946.     pwunconv \- restore /etc/password from /etc/shadown 
  947.  
  948. Programs like login, su and passwd work with  either  /etc/passwd
  949. ONLY  or  with  the  added  /etc/shadow.  If there is no entry in
  950. /etc/shadow we accept the /etc/passwd as gospel [in case  someone
  951. forgot to run /usr/lib/pwconv after adding a user.]
  952.  
  953. Also /usr/include/shadow.h:
  954.  
  955. struct spwd {
  956.     char    *sp_namp; /* users login name */
  957.     char    *sp_pwdp; /* encrypted password */
  958.     long    sp_lstchg; /* number of days since January 1, 1970 
  959.                   that the password has been modified */
  960.     int    sp_max; /* the number of days required between password changes */
  961.     int    sp_min; /* the maximum number of days the password is valid. */
  962. }
  963. #define  SHADOW "/etc/shadow"
  964.  
  965. ATT doesn't provide any of the functions or the  header  file  as
  966. part  of  its  product.  It  is in the source but not the binary.
  967. Thus developers who need the  routines  must  contact  their  ATT
  968. person [not me!] to obtain the shadow password security library
  969. -- 
  970. =Dennis L. Mumaugh
  971.  Lisle, IL       ...!{att,lll-crg}!cuuxb!dlm  OR cuuxb!dlm@arpa.att.com
  972.  
  973.  
  974. SHAR_EOF
  975. fi
  976. if test -f 'pmain.c'
  977. then
  978.     echo shar: "will not over-write existing file 'pmain.c'"
  979. else
  980. cat << \SHAR_EOF > 'pmain.c'
  981. #include <sys/types.h>
  982. #include <stdio.h>
  983. #include <pwd.h>
  984. #include <fcntl.h>
  985. #include <signal.h>
  986. #include <errno.h>
  987. #include <string.h>
  988. #include "config.h"
  989. #include "lastlog.h"
  990. #include "shadow.h"
  991.  
  992. char    name[BUFSIZ];
  993. char    orig[BUFSIZ];
  994. char    pass[BUFSIZ];
  995. char    pass2[BUFSIZ];
  996.  
  997. struct    passwd    pwent;
  998.  
  999. #ifndef    RETRIES
  1000. #define    RETRIES    3
  1001. #endif
  1002.  
  1003. char    *l64a ();
  1004. char    *crypt ();
  1005. extern    int    errno;
  1006. long    a64l ();
  1007. void    entry ();
  1008. time_t    time ();
  1009.  
  1010. int    main (argc, argv)
  1011. int    argc;
  1012. char    **argv;
  1013. {
  1014.     char    *cp;
  1015.     char    *getlogin ();
  1016.     int    amroot;
  1017.     int    lockfd = -1;
  1018. #ifdef    OBSCURE
  1019.     int    force = 0;
  1020. #endif
  1021.     int    retries;
  1022. #ifdef    AGING
  1023.     long    week;
  1024.     long    lastweek;
  1025. #endif
  1026.     long    salttime;
  1027.     struct    passwd    *pw;
  1028.     struct    passwd    *getpwuid ();
  1029.     struct    passwd    *sgetpwent ();
  1030.     FILE    *npwd;
  1031. #ifdef    SHADOWPWD
  1032.     struct    spwd    *spwd;
  1033.     struct    spwd    tspwd;
  1034. #else
  1035.     FILE    *pwd;
  1036.     char    buf[BUFSIZ];
  1037. #endif
  1038.  
  1039.     argc--; argv++;            /* shift ... */
  1040.  
  1041.     if (! (pw = getpwuid (getuid ())))
  1042.         goto failure;        /* can't get my name ... */
  1043.         
  1044. #ifdef    OBSCURE
  1045.     if (argc > 0 && strcmp (argv[0], "-f") == 0) {
  1046.         force = 1;
  1047.         argc--; argv++;        /* shift ... */
  1048.     }
  1049. #endif
  1050.     if (argc > 0)
  1051.         (void) strcpy (name, argv[0]);
  1052.     else if (cp = getlogin ())    /* need user name */
  1053.         (void) strcpy (name, cp);
  1054.     else                /* can't find user name! */
  1055.         goto failure;
  1056.  
  1057.     printf ("Changing password for %s\n", name);
  1058.  
  1059.     amroot = getuid () == 0;    /* currently am super user */
  1060.     if (! amroot)
  1061.         force = 0;
  1062.  
  1063.     if (! amroot && strcmp (name, pw->pw_name) != 0)
  1064.         goto failure;
  1065.  
  1066.     entry (name, &pwent);        /* get password file entry */
  1067.  
  1068.     if (! pwent.pw_name)        /* no entry for user??? */
  1069.         goto failure;
  1070.  
  1071.     if (! amroot) {
  1072.         if (! password ("Old Password:", orig))
  1073.             exit (1);
  1074.  
  1075.         if (! valid (orig, &pwent)) {
  1076.             puts ("Sorry.");
  1077.             exit (1);
  1078.         }
  1079.     }
  1080. #ifdef    AGING
  1081.     if (! amroot && pwent.pw_age) {    /* check out the age */
  1082. #ifdef    SHADOWPWD
  1083.         (void) time (&week);
  1084.         week /= (24L * 60L * 60L);    /* days since epoch */
  1085.         if (spwd = getspnam (name)) {    /* use entries in shadow */
  1086.             if (spwd->sp_min > spwd->sp_max) {
  1087.                 puts ("You may not change this password");
  1088.                 exit (1);
  1089.             }
  1090.             if (spwd->sp_lstchg + spwd->sp_min > week) {
  1091.                 printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
  1092.                 exit (1);
  1093.             }
  1094.         } else {
  1095. #endif    /* SHADOWPWD */
  1096.         (void) time (&week);
  1097.         week /= (7L * 24L * 60L * 60L);    /* weeks since epoch */
  1098.         lastweek = a64l (&pwent.pw_age[2]);
  1099.  
  1100.         if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
  1101.             puts ("You may not change this password");
  1102.             exit (1);
  1103.         }
  1104.         if (c64i (pwent.pw_age[1]) + lastweek > week) {
  1105.             printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
  1106.             exit (1);
  1107.         }
  1108. #ifdef    SHADOWPWD
  1109.         }
  1110. #endif
  1111.     }
  1112. #endif
  1113.     printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
  1114. #ifdef    OBSCURE
  1115.     puts ("Please use a combination of upper and lowercase letters and numbers");
  1116. #endif
  1117.     retries = RETRIES;
  1118. retry:
  1119.     if (! password ("New Password:", pass))
  1120.         exit (1);
  1121.  
  1122.     if (!force && ! obscure ()) {
  1123. #ifdef    OBSCURE
  1124.         puts ("Password not changed.");
  1125.         exit (1);
  1126. #else
  1127.         if (retries-- > 0) {
  1128.             puts ("Please try again.");
  1129.             goto retry;
  1130.         } else
  1131.             goto toomany;
  1132. #endif
  1133.     }
  1134.     if (! password ("Re-enter new password:", pass2))
  1135.         exit (1);
  1136.  
  1137.     if (strcmp (pass, pass2) != 0) {
  1138.         puts ("They don't match; try again");
  1139.  
  1140.         if (retries-- > 0)
  1141.             goto retry;
  1142.         else
  1143.             goto toomany;
  1144.     }
  1145. #ifdef    AGING
  1146.     if (pwent.pw_age) {
  1147.         cp = l64a (week);
  1148.  
  1149.         pwent.pw_age[2] = cp[0];
  1150.         pwent.pw_age[3] = cp[1];
  1151.         pwent.pw_age[4] = '\0';
  1152.     }
  1153. #endif
  1154.     (void) time (&salttime);
  1155.     salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
  1156.     pwent.pw_passwd = crypt (pass, l64a (salttime));
  1157.  
  1158.     /*
  1159.      * Now we get to race the bad guy.  I don't think he can get us.
  1160.      *
  1161.      * Ignore most reasonable signals.
  1162.      *    Maybe we should ignore more?  He can't hurt us until the end.
  1163.      *
  1164.      * Get a lock file.
  1165.      *
  1166.      * Copy first part of password file to new file.
  1167.      *    Illegal lines are copied verbatim.
  1168.      *    File permissions are r--r--r--, owner root, group root.
  1169.      *
  1170.      * Output the new entry.
  1171.      *    Only fields in struct passwd are output.
  1172.      *
  1173.      * Copy the rest of the file verbatim.
  1174.      *
  1175.      * Rename (link, unlink) password file to backup.
  1176.      *    Kill me now and nothing changes or no one gets in.
  1177.      *
  1178.      * Rename (link, unlink) temporary file to password file.
  1179.      *    Kill me now and no one gets in or lock is left.
  1180.      *
  1181.      * Remove locking file.
  1182.      *
  1183.      * That's all folks ...
  1184.      */
  1185.  
  1186.     signal (SIGINT, SIG_IGN);
  1187.     signal (SIGQUIT, SIG_IGN);
  1188.     signal (SIGTERM, SIG_IGN);
  1189.  
  1190.     umask (0);            /* get new files modes correct */
  1191. #ifndef    NDEBUG
  1192.     if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  1193. #else
  1194.     if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  1195. #endif    /* NDEBUG */
  1196.     {
  1197.         puts ("Can't get lock");
  1198.         exit (1);
  1199.     }
  1200.     umask (077);            /* close security holes to come ... */
  1201. #ifdef    SHADOWPWD
  1202.     if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
  1203.         goto failure;
  1204.  
  1205.     if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
  1206.         goto failure;
  1207.  
  1208.     if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
  1209.         goto failure;
  1210.  
  1211.     setspent ();
  1212.  
  1213.     while (spwd = getspent ()) {
  1214.         if (strcmp (spwd->sp_namp, name) == 0)
  1215.             break;
  1216.  
  1217.         (void) putspent (spwd, npwd);
  1218.     }
  1219.     if (spwd == (struct spwd *) 0) { /* didn't find a match */
  1220.         spwd = &tspwd;        /* use a local structure instead */
  1221.         spwd->sp_namp = pwent.pw_name;
  1222.         spwd->sp_max = 10000;    /* about as big as possible */
  1223.         spwd->sp_min = 0;    /* about as small as possible */
  1224.     }
  1225.     spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */
  1226.  
  1227.     (void) time (&lastweek);    /* get the current time ... */
  1228.     lastweek /= (24L*60L*60L);    /* ... turn it into days. */
  1229.     spwd->sp_lstchg = lastweek;    /* save it as date of last change */
  1230.  
  1231.     (void) putspent (spwd, npwd);    /* add the new entry */
  1232.  
  1233.     while (spwd = getspent ())    /* finish the other ones off */
  1234.         (void) putspent (spwd, npwd);
  1235.  
  1236.     endspent ();
  1237.  
  1238.     if (ferror (npwd)) {
  1239.         perror (NSHADOW);
  1240.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  1241.             fputs ("Help!\n", stderr);
  1242.  
  1243.         exit (1);
  1244.     }
  1245.     fflush (npwd);
  1246.     fclose (npwd);
  1247.  
  1248.     if (access (OSHADOW, 0) == 0) {
  1249.         if (unlink (OSHADOW)) {
  1250.             puts ("Can't remove backup file");
  1251.             goto unlock;
  1252.         }
  1253.     }
  1254.     if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
  1255.         puts ("Can't save backup file");
  1256.         goto unlock;
  1257.     }
  1258.     if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) {
  1259.         (void) unlink (OSHADOW);
  1260.         puts ("Can't rename new file");
  1261.         goto unlock;
  1262.     }
  1263.     if (unlink (OSHADOW)) {
  1264.         puts ("Can't remove backup file");
  1265.         goto unlock;
  1266.     }
  1267. #else    /* ! SHADOWPWD */
  1268.     if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
  1269.         goto failure;
  1270.  
  1271. #ifndef    NDEBUG
  1272.     if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
  1273. #else
  1274.     umask (077);        /* no permissions for non-roots */
  1275.  
  1276.     if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
  1277. #endif    /* NDEBUG */
  1278.         goto failure;
  1279.  
  1280. #ifndef    NDEBUG
  1281.     chmod (NPWDFILE, 0444);        /* lets have some security here ... */
  1282.     chown (NPWDFILE, 0, 0);        /* ... and keep the bad guy away */
  1283. #endif    /* NDEBUG */
  1284.     if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0)
  1285.         goto failure;
  1286.  
  1287.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
  1288.         if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
  1289.             fputs (buf, npwd);
  1290.         } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
  1291.             fputs (buf, npwd);
  1292.         else
  1293.             break;
  1294.     }
  1295.     (void) fprintf (npwd, "%s:", pw->pw_name);
  1296.     if (pwent.pw_age)
  1297.         (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
  1298.     else
  1299.         (void) fprintf (npwd, "%s:", pwent.pw_passwd);
  1300.  
  1301.     (void) fprintf (npwd, "%d:%d:%s:%s:%s",
  1302.         pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir
  1303.         pwent.pw_shell ? pwent.pw_shell:"");
  1304.  
  1305.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
  1306.         fputs (buf, npwd);
  1307.  
  1308.     if (ferror (npwd)) {
  1309.         perror (NPWDFILE);
  1310.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  1311.             fputs ("Help!\n", stderr);
  1312.  
  1313.         exit (1);
  1314.     }
  1315.     fflush (npwd);
  1316.     fclose (npwd);
  1317. #ifdef    NDEBUG
  1318.     if (unlink (OPWDFILE) == -1) {
  1319.         if (errno != ENOENT) {
  1320.             puts ("Can't unlink backup file");
  1321.             goto unlock;
  1322.         }
  1323.     }
  1324.     if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
  1325.         puts ("Can't save backup file");
  1326.         goto unlock;
  1327.     }
  1328.     if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) {
  1329.         puts ("Can't rename new file");
  1330.         goto unlock;
  1331.     }
  1332. #endif    /* NDEBUG */
  1333. #endif    /* SHADOW */
  1334. #ifndef    NDEBUG
  1335.     (void) unlink (".pwdlock");
  1336. #else
  1337.     (void) unlink (PWDLOCK);
  1338. #endif
  1339.     exit (0);
  1340.     /*NOTREACHED*/
  1341.  
  1342. failure:
  1343.     puts ("Permission denied.");
  1344. unlock:
  1345.     if (lockfd >= 0)
  1346.         (void) unlink (PWDLOCK);
  1347.  
  1348.     (void) unlink (NPWDFILE);
  1349.     exit (1);
  1350.     /*NOTREACHED*/
  1351.  
  1352. toomany:
  1353.     puts ("Too many tries; try again later.");
  1354.     exit (1);
  1355.     /*NOTREACHED*/
  1356. }
  1357. SHAR_EOF
  1358. fi
  1359. if test -f 'sulogin.c'
  1360. then
  1361.     echo shar: "will not over-write existing file 'sulogin.c'"
  1362. else
  1363. cat << \SHAR_EOF > 'sulogin.c'
  1364. #include <sys/types.h>
  1365. #include <stdio.h>
  1366. #include <pwd.h>
  1367. #include <utmp.h>
  1368. #include "config.h"
  1369. #include "lastlog.h"
  1370.  
  1371. char    name[BUFSIZ];
  1372. char    pass[BUFSIZ];
  1373. char    home[BUFSIZ];
  1374. char    prog[BUFSIZ];
  1375. char    mail[BUFSIZ];
  1376.  
  1377. struct    passwd    pwent;
  1378. struct    utmp    utent;
  1379. struct    lastlog    lastlog;
  1380.  
  1381. #ifndef    MAXENV
  1382. #define    MAXENV    64
  1383. #endif
  1384.  
  1385. char    *newenvp[MAXENV];
  1386. int    newenvc = 0;
  1387. int    maxenv = MAXENV;
  1388. extern    char    **environ;
  1389.  
  1390. #ifndef    ALARM
  1391. #define    ALARM    60
  1392. #endif
  1393.  
  1394. #ifndef    RETRIES
  1395. #define    RETRIES    3
  1396. #endif
  1397.  
  1398. int    main (argc, argv, envp)
  1399. int    argc;
  1400. char    **argv;
  1401. char    **envp;
  1402. {
  1403.     char    *getenv ();
  1404.     char    *ttyname ();
  1405.     char    *cp;
  1406.  
  1407.     if (access (PWDFILE, 0) == -1) { /* must be a password file! */
  1408.         printf ("No password file\n");
  1409.         exit (1);
  1410.     }
  1411. #ifndef    DEBUG
  1412.     if (getppid () != 1)        /* parent must be INIT */
  1413.         exit (1);
  1414. #endif
  1415.     if (! isatty (0))        /* must be a terminal */
  1416.         exit (1);
  1417.  
  1418.     while (*envp)            /* add inherited environment, */
  1419.         addenv (*envp++);    /* some variables change later */
  1420.  
  1421. #ifdef    TZ
  1422.     addenv (TZ);            /* set the default $TZ, if one */
  1423. #endif
  1424. #ifdef    HZ
  1425.     addenv (HZ);            /* set the default $HZ, if one */
  1426. #endif
  1427.     (void) strcpy (name, "root");    /* KLUDGE!!! */
  1428.  
  1429.     while (1) {        /* repeatedly get login/password pairs */
  1430.         entry (name, &pwent);    /* get entry from password file */
  1431.         if (pwent.pw_name == (char *) 0) {
  1432.             printf ("No password entry for 'root'\n");
  1433.             exit (1);
  1434.         }
  1435.  
  1436.     /*
  1437.      * Here we prompt for the root password, or if no password is
  1438.      * given we just exit and let INIT go to runlevel 2.
  1439.      */
  1440.  
  1441.                     /* get a password for root */
  1442.         if (! password ("Type control-d for normal startup,\n(or give root password for system maintenance):", pass))
  1443.             exit (0);
  1444.  
  1445.         if (valid (pass, &pwent)) /* check encrypted passwords ... */
  1446.             break;        /* ... encrypted passwords matched */
  1447.  
  1448.         puts ("Login incorrect");
  1449.     }
  1450.     environ = newenvp;        /* make new environment active */
  1451.  
  1452.     puts ("Entering System Maintenance Mode");
  1453.  
  1454.     /*
  1455.      * Normally there would be a utmp entry for login to mung on
  1456.      * to get the tty name, date, etc. from.  We don't need all that
  1457.      * stuff because we won't update the utmp or wtmp files.  BUT!,
  1458.      * we do need the tty name so we can set the permissions and
  1459.      * ownership.
  1460.      */
  1461.  
  1462.     if (cp = ttyname (0))        /* found entry in /dev/ */
  1463.         strcpy (utent.ut_line, cp); /* needed for tty perms (setup) */
  1464.         
  1465.     if (getenv ("IFS"))        /* don't export user IFS ... */
  1466.         addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  1467.  
  1468.     setup (&pwent);            /* set UID, GID, HOME, etc ... */
  1469.  
  1470.     shell (pwent.pw_shell);        /* exec the shell finally. */
  1471.     /*NOTREACHED*/
  1472. }
  1473. SHAR_EOF
  1474. fi
  1475. if test -f 'dialup.h'
  1476. then
  1477.     echo shar: "will not over-write existing file 'dialup.h'"
  1478. else
  1479. cat << \SHAR_EOF > 'dialup.h'
  1480. /*
  1481.  * Structure of d_passwd file
  1482.  *
  1483.  *    The d_passwd file contains the names of login shells which require
  1484.  *    dialup passwords.  Each line contains the fully qualified path name
  1485.  *    for the shell, followed by an optional password.  Each field is
  1486.  *    separated by a ':'.
  1487.  *
  1488.  * Structure of the dialups file
  1489.  *
  1490.  *    The dialups file contains the names of ports which may be dialup
  1491.  *    lines.  Each line consists of the last component of the path
  1492.  *    name.  Any leading directory names are removed.
  1493.  */
  1494.  
  1495. struct    dialup {
  1496.     char    *du_shell;
  1497.     char    *du_passwd;
  1498. };
  1499.  
  1500. void    setduent ();
  1501. void    endduent ();
  1502. struct    dialup    *getduent ();
  1503. struct    dialup    *getdushell ();
  1504.  
  1505. #define    DIALPWD    "/etc/d_passwd"
  1506. #define    DIALUPS    "/etc/dialups"
  1507. SHAR_EOF
  1508. fi
  1509. exit 0
  1510. #    End of shell archive
  1511.